// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
//  »Project«   Talina Gaming System (TgS) (∂)
//  »File«      TgS Common - Math API [Matrix] [F] [F].i_inc
//  »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
//  »Version«   4.0
// ------------------------------------------------------------------------------------------------------------------------------ //
//  Copyright: © 2002-2010, Andrew Aye.  All Rights Reserved.
//  This software is free for non-commercial use. Redistribution and use in source and binary forms, with or without modification,
//  are permitted provided that the following conditions are met: 
//    Redistributions of source code must retain this copyright notice, this list of conditions and the following disclaimers. 
//    Redistributions in binary form must reproduce this copyright notice, this list of conditions and the following
//      disclaimers in the documentation and other materials provided with the distribution. 
//  Neither the names of the copyright owner nor the names of its contributors may be used to endorse or promote products derived
//  from this software without specific prior written permission. 
//  The intellectual property rights of the algorithms used reside with Andrew Aye.  You may not use this software, in whole or
//  in part, in support of any commercial product without the express written consent of the author.
//  There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is".
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //

// ---- PER-VECTOR ARITHMETIC OPERATIONS ---------------------------------------------------------------------------------------- //

TgINLINE TgVOID M(F_ADD_MM)( M(PCU_TgMAT) ptmRet, M(CPCU_TgMAT) ptmM0, M(CPCU_TgMAT) ptmM1 )
{
    #define EQN(A) V(F_ADD_VV)( ptmM0->m_atvRow + A, ptmM1->m_atvRow + A )
    MAT_ASSIGN
    #undef EQN
}


TgINLINE TgVOID M(F_MUL_MM)( M(PCU_TgMAT) ptmRet, M(CPCU_TgMAT) ptmM0, M(CPCU_TgMAT) ptmM1 )
{
    #define EQN(A) V(F_MUL_VV)( ptmM0->m_atvRow + A, ptmM1->m_atvRow + A )
    MAT_ASSIGN
    #undef EQN
}


TgINLINE TgVOID M(F_MUL_SM)( M(PCU_TgMAT) ptmRet, const TYPE tyScalar, M(CPCU_TgMAT) ptmM1 )
{
    #define EQN(A) V(F_MUL_SV)( tyScalar, ptmM1->m_atvRow + A )
    MAT_ASSIGN
    #undef EQN
}


TgINLINE TgVOID M(F_MUL_MS)( M(PCU_TgMAT) ptmRet, M(CPCU_TgMAT) ptmM0, const TYPE tyScalar )
{
    #define EQN(A) V(F_MUL_VS)( ptmM0->m_atvRow + A, tyScalar )
    MAT_ASSIGN
    #undef EQN
}


TgINLINE TgVOID M(F_DIV_MM)( M(PCU_TgMAT) ptmRet, M(CPCU_TgMAT) ptmM0, M(CPCU_TgMAT) ptmM1 )
{
    #define EQN(A) V(F_DIV_VV)( ptmM0->m_atvRow + A, ptmM1->m_atvRow + A )
    MAT_ASSIGN
    #undef EQN
}


TgINLINE TgVOID M(F_DIV_SM)( M(PCU_TgMAT) ptmRet, const TYPE tyScalar, M(CPCU_TgMAT) ptmM1 )
{
    #define EQN(A) V(F_DIV_SV)( tyScalar, ptmM1->m_atvRow + A )
    MAT_ASSIGN
    #undef EQN
}


TgINLINE TgVOID M(F_DIV_MS)( M(PCU_TgMAT) ptmRet, M(CPCU_TgMAT) ptmM0, const TYPE tyScalar )
{
    #define EQN(A) V(F_DIV_VS)( ptmM0->m_atvRow + A, tyScalar )
    MAT_ASSIGN
    #undef EQN
}


TgINLINE TgVOID M(F_SUB_MM)( M(PCU_TgMAT) ptmRet, M(CPCU_TgMAT) ptmM0, M(CPCU_TgMAT) ptmM1 )
{
    #define EQN(A) V(F_SUB_VV)( ptmM0->m_atvRow + A, ptmM1->m_atvRow + A )
    MAT_ASSIGN
    #undef EQN
}


TgINLINE TgVOID M(F_NEG_MM)( M(PCU_TgMAT) ptmRet, M(CPCU_TgMAT) ptmM0 )
{
    #define EQN(A) V(F_NEG)( ptmM0->m_atvRow + A )
    MAT_ASSIGN
    #undef EQN
}




// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
//  Scalar Function
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //

// ---- SET ROTATION [[0..2][0..2]] --------------------------------------------------------------------------------------------- //

TgINLINE TgVOID M(F_SET_EUL_V3)( M(PCU_TgMAT) ptmM0, V3(CPCU_TgVEC) ptvEul )
{
    M(F_SET_EUL_ELEM)( ptmM0, ptvEul->m.x, ptvEul->m.y, ptvEul->m.z );
}


TgINLINE TgVOID M(F_SET_EUL_V4)( M(PCU_TgMAT) ptmM0, V4(CPCU_TgVEC) ptvEul )
{
    M(F_SET_EUL_ELEM)( ptmM0, ptvEul->m.x, ptvEul->m.y, ptvEul->m.z );
}


TgINLINE TgVOID M(F_SET_EUL_ELEM)( M(PCU_TgMAT) ptmM0, const TYPE tyX, const TYPE tyY, const TYPE tyZ )
{
    TYPE                                tySinZ,tyCosZ, tySinX,tyCosX, tySinY,tyCosY;

    F(tgPM_SINCOS)( &tySinX, &tyCosX, tyX ); //« Roll
    F(tgPM_SINCOS)( &tySinY, &tyCosY, tyY ); //« Pitch
    F(tgPM_SINCOS)( &tySinZ, &tyCosZ, tyZ ); //« Yaw

    ptmM0->m.f11 = tyCosY*tyCosZ;
    ptmM0->m.f12 = tyCosY*tySinZ;
    ptmM0->m.f13 = -tySinY;

    ptmM0->m.f21 = tySinX*tySinY*tyCosZ - tyCosX*tySinZ;
    ptmM0->m.f22 = tySinX*tySinY*tySinZ + tyCosX*tyCosZ;
    ptmM0->m.f23 = tySinX*tyCosY;

    ptmM0->m.f31 = tyCosX*tySinY*tyCosZ + tySinX*tySinZ;
    ptmM0->m.f32 = tyCosX*tySinY*tySinZ - tySinX*tyCosZ;
    ptmM0->m.f33 = tyCosX*tyCosY;
}


TgINLINE TgVOID M(F_SET_ELX)( M(PCU_TgMAT) ptmM0, const TYPE tyX )
{
    TYPE                                tySinX,tyCosX;

    F(tgPM_SINCOS)( &tySinX, &tyCosX, tyX );

    ptmM0->m.f11 = MKL(1.0); ptmM0->m.f12 = MKL(0.0); ptmM0->m.f13 = MKL(0.0);
    ptmM0->m.f21 = MKL(0.0); ptmM0->m.f22 = tyCosX;   ptmM0->m.f23 = tySinX;
    ptmM0->m.f31 = MKL(0.0); ptmM0->m.f32 =-tySinX;   ptmM0->m.f33 = tyCosX;
}


TgINLINE TgVOID M(F_SET_ELY)( M(PCU_TgMAT) ptmM0, const TYPE tyY )
{
    TYPE                                tySinY,tyCosY;

    F(tgPM_SINCOS)( &tySinY, &tyCosY, tyY );

    ptmM0->m.f11 = tyCosY;   ptmM0->m.f12 = MKL(0.0); ptmM0->m.f13 =-tySinY;
    ptmM0->m.f21 = MKL(0.0); ptmM0->m.f22 = MKL(1.0); ptmM0->m.f23 = MKL(0.0);
    ptmM0->m.f31 = tySinY;   ptmM0->m.f32 = MKL(0.0); ptmM0->m.f33 = tyCosY;
}


TgINLINE TgVOID M(F_SET_ELZ)( M(PCU_TgMAT) ptmM0, const TYPE tyZ )
{
    TYPE                                tySinZ,tyCosZ;

    F(tgPM_SINCOS)( &tySinZ, &tyCosZ, tyZ );

    ptmM0->m.f11 = tyCosZ;   ptmM0->m.f12 = tySinZ;   ptmM0->m.f13 = MKL(0.0);
    ptmM0->m.f21 =-tySinZ;   ptmM0->m.f22 = tyCosZ;   ptmM0->m.f23 = MKL(0.0);
    ptmM0->m.f31 = MKL(0.0); ptmM0->m.f32 = MKL(0.0); ptmM0->m.f33 = MKL(1.0);
}


TgINLINE TgVOID M(F_SET_ROT)( M(PCU_TgMAT) ptmM0, V4(CPCU_TgVEC) ptqR0 )
{
    const TYPE                          tyXS = MKL(2.0) * ptqR0->m.x;
    const TYPE                          tyYS = MKL(2.0) * ptqR0->m.y;
    const TYPE                          tyZS = MKL(2.0) * ptqR0->m.z;

    const TYPE                          tyXX = tyXS * ptqR0->m.x;
    const TYPE                          tyXY = tyXS * ptqR0->m.y;
    const TYPE                          tyXZ = tyXS * ptqR0->m.z;
    const TYPE                          tyXW = tyXS * ptqR0->m.w;

    const TYPE                          tyYY = tyYS * ptqR0->m.y;
    const TYPE                          tyYZ = tyYS * ptqR0->m.z;
    const TYPE                          tyYW = tyYS * ptqR0->m.w;

    const TYPE                          tyZZ = tyZS * ptqR0->m.z;
    const TYPE                          tyZW = tyZS * ptqR0->m.w;

    ptmM0->m.f11 = MKL(1.0) - ( tyYY + tyZZ );
    ptmM0->m.f12 = tyXY + tyZW;
    ptmM0->m.f13 = tyXZ - tyYW;

    ptmM0->m.f21 = tyXY - tyZW;
    ptmM0->m.f22 = MKL(1.0) - ( tyXX + tyZZ );
    ptmM0->m.f23 = tyYZ + tyXW;

    ptmM0->m.f31 = tyXZ + tyYW;
    ptmM0->m.f32 = tyYZ - tyXW;
    ptmM0->m.f33 = MKL(1.0) - ( tyXX + tyYY );
}